package com.zgg.files.controller;


import com.alibaba.fastjson.JSONObject;
import com.zgg.base.BaseController;
import com.zgg.config.AliOssProperties;
import com.zgg.files.bean.OSSFile;
import com.zgg.files.service.impl.UploadServiceImpl;
import com.zgg.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author Administrator
 */
@RequestMapping("/fastdfs")
@RestController
public class FileUploadController extends BaseController {
    @Autowired
    private UploadServiceImpl uploadService;

    @Autowired
    private AliOssProperties aliOssProperties;

    @Autowired
    private Environment env;

    @Autowired
    private CallbackUtils callbackUtils;

    /**
     * 对回调的内容进行验证
     *
     * @param callBackContent
     * @param sign
     * @param code
     * @return
     */
    private boolean validateCallBack(String callBackContent, String sign, String code) {
        String key = MD5Utils.encrypt(code);
        String result = HMACSHA256Utils.sha256_HMAC(callBackContent, key);
        return sign.equals(result);
    }


    /**
     * oss
     * 批量上传
     *
     * @param request
     * @param userid   上传文件的用户id（非必要）
     * @param usertype 上传文件的用户身份（1:2：非必要）
     * @param pathcode 旧文件系统中文件的唯一标识pathcode（非必要）
     * @param callback 上传文件后，需要文件服务回调使用的参数。（非必要）
     *                 此参数结构：
     *                 ｛
     *                 "callbackBody":{
     *                 "url":
     *                 "args":{
     *                 "key":"value"
     *                 }
     *                 },
     *                 "sign":签名
     *                 "code":随机字符串
     *                 ｝
     *                 callbackBody为base64加密后的结果
     *                 code为一个16位用数字0-9，a-z，A-Z的随机数。
     *                 sign为callbackBody加密后的一个结果。加密步骤为：
     *                 1、将code使用md5加密，做为密钥
     *                 2、将callbackBody进行base64加密
     *                 3、使用Hmacsha256对callbackBody进行加密
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/uploadFileNew", method = RequestMethod.POST)
    public JSONObject uploadFiles(HttpServletRequest request,
                                  @RequestParam(value = "userid", required = false) final Integer userid,
                                  @RequestParam(value = "usertype", required = false) final Integer usertype,
                                  @RequestParam(value = "pathcode", required = false) final String pathcode,
                                  @RequestParam(value = "callback", required = false) String callback) {
        long startTime = System.currentTimeMillis();

        int msgCode = 200;
        String message = "";
        JSONObject jsonObject = new JSONObject();

        //1、文件上传到本地服务器
        List<String> list = FileUtils.springFileUpload(request, env.getProperty("ali.localUrl"));
        JSONObject callBackJson = null;

        //如果callback不为空，将其转为json对象，并将文件名和其唯一id做为参数进行传递。
        if (callback != null && callback.trim().length() > 0) {
            callBackJson = JSONObject.parseObject(callback);
            //验证call不为空
            if (callBackJson.containsKey("callbackBody") && callBackJson.containsKey("sign") &&
                    callBackJson.containsKey("code")) {
                String callbackBody = callBackJson.getString("callbackBody");
                String sign = callBackJson.getString("sign");
                String code = callBackJson.getString("code");
                if (!validateCallBack(callbackBody, sign, code)) {
                    msgCode = 202;
                    message = "callback加密验证不通过";
                    return returnResult(msgCode, jsonObject, message);
                }
            } else {
                msgCode = 201;
                message = "callback参数错误";
                return returnResult(msgCode, jsonObject, message);
            }
        } else {
            callBackJson = new JSONObject();
        }

        //2、初步在数据库里插入一条数据，记录文件名与分配唯一id。

        final List<OSSFile> ossFiles = new ArrayList<>();
        Map<String, String> fileMap = new HashMap<>();
        Map<String, String> resultMap = new HashMap<>();
        for (String localPath : list) {
            OSSFile ossFile = new OSSFile();

            String uuid = UUIDUtils.IdGenerate();
            // + DateUtils.getDateByFormat(new Date(), "yyyy");

            ossFile.setId(uuid);
            String fileName = localPath.replace(env.getProperty("ali.localUrl"), "");
            ossFile.setFname(fileName);
            ossFile.setAddtime(new Date());
            ossFile.setAdduserid(userid);
            ossFile.setAddusertype(usertype);
            ossFile.setPathcode(pathcode);
            ossFiles.add(ossFile);

            fileMap.put(localPath, uuid);

            resultMap.put(fileName, uuid);
        }

        //3、文件上传到oss
        uploadService.uploadOSSFile(fileMap, aliOssProperties, callBackJson);

        //4、数据入库
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                uploadService.uploadFileInfo(ossFiles);
            }

        };

        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        cachedThreadPool.execute(runnable);
        //try {
        //    runnable.run();
        //} catch (Exception e) {
        //    e.printStackTrace();
        //}
        //5、返回文件id
        jsonObject.putAll(resultMap);
        msgCode = 200;
        message = "上传中，请等待...";
        long endTime = System.currentTimeMillis();
        logger.error("=============>>>>>>        controller响应时间：【" + (endTime - startTime) + "】ms");
        return returnResult(msgCode, jsonObject, message);
    }


    /**
     * oss file 回调接口
     *
     * @param bucket
     * @param object
     * @param mimeType
     * @param size
     * @param request
     * @param response
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/uploadCallBack", method = RequestMethod.POST)
    public String uploadFileCallBack(
            @RequestParam(value = "bucket", required = false) String bucket,
            @RequestParam(value = "object", required = false) String object,
            @RequestParam(value = "mimeType", required = false) String mimeType,
            @RequestParam(value = "size", required = false) String size,
            HttpServletRequest request,
            HttpServletResponse response) {
        logger.error("==============>>>>>>>>       回调接口被回调!!!!");
        long startTime = System.currentTimeMillis();
        //获取callback的返回参数
        final String clientCallBackBody = request.getParameter("clientCallBackBody");
        final String fileName = request.getParameter("fileName");
        final String fileId = request.getParameter("fileId");

        logger.warn("========>>>>>> 回调成功：返回参数为：【bucket:" + bucket + "】【object:" + object + "】【mimeType:" + mimeType + "】" +
                "【size:" + size + "】【fileId:" + fileId + "】【fileName:" + fileName + "】【clientCallBackBody:" + clientCallBackBody + "】");

        //将文件在oss上的信息写入数据库
        OSSFile ossFile = uploadService.findOssFileById(fileId);
        int fileType = mimeType.indexOf("image") != -1 ? 1 : 2;
        ossFile.setFiletype(fileType);
        ossFile.setFpath(object);
        ossFile.setSize(Long.valueOf(size));
        ossFile.setUpdatetime(new Date());
        ossFile.setUpdateuserid(0);
        ossFile.setUpdateusertype(3);
        int num = uploadService.updateFileInfo(ossFile);
        logger.info("=========>>>>>>>   修改fileName【" + ossFile.getFname() + "】信息成功");

        //对client进行回调
        Callable callable = new Callable<Object>() {
            @Override
            public Object call() {
                try {
                    callbackUtils.clientCallBack(clientCallBackBody, fileName, fileId);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            }
        };
        try {
            callable.call();
        } catch (Exception e) {
            e.printStackTrace();
        }

        response.setStatus(HttpServletResponse.SC_OK);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("success", true);
        long endTime = System.currentTimeMillis();
        logger.error("=============>>>>>>        oss callback 响应时间：【" + (endTime - startTime) + "】ms");
        return jsonObject.toString();
    }

    /**
     * 批量下载文件并打成zip包
     * 返回文件流
     *
     * @param fileIds
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getZipFiles", method = RequestMethod.POST)
    public ResponseEntity getZipFiles(@RequestParam(value = "fileIds", required = false) String[] fileIds) {
        File file = null;
        List<String> list = new ArrayList<>();
        if (fileIds.length > 0) {
            for (int i = 0; i < fileIds.length; i++) {
                list.add(fileIds[i]);
            }
            file = uploadService.downOSSFile(list, aliOssProperties);
        }

        return export(file);

    }

    /**
     * 根据文件path浏览
     * 返回文件流
     *
     * @param filePath
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFileByPath", method = RequestMethod.POST)
    public ResponseEntity getFileByPath(@RequestParam(value = "filePath", required = false) String filePath) {
        JSONObject jsonObject = new JSONObject();
        if (filePath == null && filePath.trim().length() == 0 && "".equals(filePath)) {
            jsonObject.put("status", 201);
            jsonObject.put("msg", "文件路径为空！");
            return export(jsonObject);
        }
        OSSFile ossFile = uploadService.findOssFileByPath(filePath);
        String errorMsg = "";
        if (ossFile == null) {
            errorMsg = "filePath：【" + filePath + "】为空或者错误，请重新确认";
            jsonObject.put("status", 201);
            jsonObject.put("msg", errorMsg);
            logger.error("==========>>>>     " + errorMsg);
            return export(jsonObject);
        } else {
            File file = uploadService.downOSSFile(ossFile, aliOssProperties);
            if (file == null || file.length() == 0) {
                jsonObject.put("status", 201);
                jsonObject.put("msg", "文件路径出错，请重新确认！");
                return export(jsonObject);
            } else {
                return export(file);
            }
        }
    }


    /**
     * 根据文件Id浏览
     * 返回文件流
     *
     * @param fileId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFileById/{fileId}", method = RequestMethod.GET)
    public ResponseEntity getFileById(@PathVariable(value = "fileId", required = false) String fileId) {

        OSSFile ossFile = uploadService.findOssFileById(fileId);
        JSONObject jsonObject = new JSONObject();
        File file = null;
        String errorMsg = "";
        if (ossFile == null) {
            errorMsg = "fileId：【" + fileId + "】为空或者错误，请重新确认";
            jsonObject.put("status", 201);
            jsonObject.put("msg", errorMsg);
            logger.error("==========>>>>     " + errorMsg);
            return export(jsonObject);
        } else {
            if (ossFile.getFpath() == null || ossFile.getFpath().trim().length() == 0) {
                errorMsg = "fileId：【" + fileId + "】正在上传中，请等待...";
                jsonObject.put("status", 202);
                jsonObject.put("msg", errorMsg);
                logger.error("==========>>>>    " + errorMsg);
                return export(jsonObject);
            } else {
                file = uploadService.downOSSFile(ossFile, aliOssProperties);
                if (file == null || file.length() == 0) {
                    jsonObject.put("status", 201);
                    jsonObject.put("msg", "文件路径出错，请重新确认！");
                    return export(jsonObject);
                } else {
                    return export(file);
                }
            }
        }
    }

    /**
     * 根据fileId返回文件基本信息
     *
     * @param fileId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFileInfo/{fileId}", method = RequestMethod.GET)
    public JSONObject getFileInfo(@PathVariable(value = "fileId", required = false) String fileId) {
        OSSFile ossFile = uploadService.findOssFileById(fileId);
        JSONObject jsonObject = new JSONObject();
        if (ossFile != null) {
            return returnResult(200, ossFile, "");
        } else {
            return returnResult(201, jsonObject, "id错误");
        }
    }


    /**
     * 批量根据fileId返回文件浏览url
     *
     * @param fileIds
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFileUrlAll", method = RequestMethod.POST)
    public JSONObject getFileUrlAll(@RequestParam(value = "fileIds") String[] fileIds) {

        List<String> ids = new ArrayList<>();
        ids.addAll(Arrays.asList(fileIds));
        Map<String, String> ossFileByIds = uploadService.getOssFileByIds(ids, aliOssProperties);
        if (ossFileByIds != null) {
            return returnResult(200, ossFileByIds, "成功！");
        } else {
            return returnResult(201, ossFileByIds, "没有找结果！");
        }

    }


    /**
     * 根据fileId返回文件浏览url
     *
     * @param fileId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/getFileBrowseUrl/{fileId}", method = RequestMethod.GET)
    public JSONObject getFileBrowseUrl(@PathVariable(value = "fileId", required = false) String fileId) {
        JSONObject jsonObject = new JSONObject();
        if (fileId != null && !"".equals(fileId)) {
            String filePath = uploadService.getOSSFilePath(fileId, aliOssProperties);
            jsonObject.put("filepath", filePath);
            return returnResult(200, jsonObject, "成功！");
        } else {
            return returnResult(201, null, "文件id为空!");
        }
    }


    /**
     * 根据fileId删除文件
     *
     * @param fileId
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/deleteFile/{fileId}", method = RequestMethod.DELETE)
    public JSONObject deleteFile(@PathVariable(value = "fileId", required = false) String fileId) {
        JSONObject jsonObject = new JSONObject();
        int num = uploadService.deleteFileInfo(fileId, aliOssProperties);
        if (num > 0) {
            return returnResult(200, null, "删除成功！");
        } else {
            return returnResult(201, null, "文件删除失败或文件不存在！");
        }
    }

}
